﻿using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using xxpl1.Cache;
using xxpl1.GAE;
using xxpl1.Log;
using xxpl1.Utils;
using HttpListener = xxpl1.Proxy.HttpListener;

namespace xxpl1
{
    internal class Program
    {
        private static readonly Regex googleHostRegex = new Regex("CN=[^\\.]+\\.google\\.com", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        private static void Main(string[] args)
        {
            Win32.HandlerRoutine hr = new Win32.HandlerRoutine(Handler);

            Win32.SetConsoleCtrlHandler(hr, true);

            GC.KeepAlive(hr);

            LogManager.SetLogger(new ConsoleLogger());

            ServicePointManager.DefaultConnectionLimit = 32;
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.ServerCertificateValidationCallback += TrustAll;
            ServicePointManager.CheckCertificateRevocationList = true;

            Task.Factory.StartNew(DnsHelper.TestAccessbility);

            var listener = new HttpListener(Settings.Instance.Port);

            listener.Start();

            Console.WriteLine("Proxy Started at port: " + Settings.Instance.Port);
            Console.Read();

            Console.WriteLine("Exit");

        }

        static Boolean Handler(Win32.CtrlTypes ctrlType)
        {
            if (Settings.Instance.EnableCache)
                DiskCacheFactory.GetDiskCache().Dispose();
            return true;
        }

        private static bool TrustAll(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
        {
            if (sslpolicyerrors == SslPolicyErrors.None)
                return true;
            if (sslpolicyerrors == SslPolicyErrors.RemoteCertificateNameMismatch)
            {
                return googleHostRegex.IsMatch(certificate.Subject);
            }

            LogManager.GetLogger("Cert").DebugFormat("Cert rejected.{0},{1}", certificate.Subject, certificate.Issuer);
            return false;
        }
    }
}